/*! @azure/msal-browser v2.38.3 2023-10-27 */
'use strict';
import { __extends, __awaiter, __generator, __assign } from '../_virtual/_tslib.js';
import { PerformanceEvents, Constants, ServerError, InteractionRequiredAuthError, InteractionRequiredAuthErrorMessage } from '@azure/msal-common';
import { DEFAULT_REQUEST, InteractionType, CacheLookupPolicy, ApiId, BrowserConstants } from '../utils/BrowserConstants.js';
import { ClientApplication } from './ClientApplication.js';
import { EventType } from '../event/EventType.js';
import { BrowserAuthError } from '../error/BrowserAuthError.js';
import { NativeAuthError } from '../error/NativeAuthError.js';
import { NativeMessageHandler } from '../broker/nativeBroker/NativeMessageHandler.js';
import { BrowserUtils } from '../utils/BrowserUtils.js';

/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */
/**
 * The PublicClientApplication class is the object exposed by the library to perform authentication and authorization functions in Single Page Applications
 * to obtain JWT tokens as described in the OAuth 2.0 Authorization Code Flow with PKCE specification.
 */
var PublicClientApplication = /** @class */ (function (_super) {
    __extends(PublicClientApplication, _super);
    /**
     * @constructor
     * Constructor for the PublicClientApplication used to instantiate the PublicClientApplication object
     *
     * Important attributes in the Configuration object for auth are:
     * - clientID: the application ID of your application. You can obtain one by registering your application with our Application registration portal : https://portal.azure.com/#blade/Microsoft_AAD_IAM/ActiveDirectoryMenuBlade/RegisteredAppsPreview
     * - authority: the authority URL for your application.
     * - redirect_uri: the uri of your application registered in the portal.
     *
     * In Azure AD, authority is a URL indicating the Azure active directory that MSAL uses to obtain tokens.
     * It is of the form https://login.microsoftonline.com/{Enter_the_Tenant_Info_Here}
     * If your application supports Accounts in one organizational directory, replace "Enter_the_Tenant_Info_Here" value with the Tenant Id or Tenant name (for example, contoso.microsoft.com).
     * If your application supports Accounts in any organizational directory, replace "Enter_the_Tenant_Info_Here" value with organizations.
     * If your application supports Accounts in any organizational directory and personal Microsoft accounts, replace "Enter_the_Tenant_Info_Here" value with common.
     * To restrict support to Personal Microsoft accounts only, replace "Enter_the_Tenant_Info_Here" value with consumers.
     *
     * In Azure B2C, authority is of the form https://{instance}/tfp/{tenant}/{policyName}/
     * Full B2C functionality will be available in this library in future versions.
     *
     * @param configuration object for the MSAL PublicClientApplication instance
     */
    function PublicClientApplication(configuration) {
        var _this = _super.call(this, configuration) || this;
        _this.astsAsyncMeasurement = undefined;
        _this.activeSilentTokenRequests = new Map();
        // Register listener functions
        _this.trackPageVisibility = _this.trackPageVisibility.bind(_this);
        return _this;
    }
    /**
     * Use when initiating the login process by redirecting the user's browser to the authorization endpoint. This function redirects the page, so
     * any code that follows this function will not execute.
     *
     * IMPORTANT: It is NOT recommended to have code that is dependent on the resolution of the Promise. This function will navigate away from the current
     * browser window. It currently returns a Promise in order to reflect the asynchronous nature of the code running in this function.
     *
     * @param request
     */
    PublicClientApplication.prototype.loginRedirect = function (request) {
        return __awaiter(this, void 0, void 0, function () {
            var correlationId;
            return __generator(this, function (_a) {
                correlationId = this.getRequestCorrelationId(request);
                this.logger.verbose("loginRedirect called", correlationId);
                return [2 /*return*/, this.acquireTokenRedirect(__assign({ correlationId: correlationId }, (request || DEFAULT_REQUEST)))];
            });
        });
    };
    /**
     * Use when initiating the login process via opening a popup window in the user's browser
     *
     * @param request
     *
     * @returns A promise that is fulfilled when this function has completed, or rejected if an error was raised.
     */
    PublicClientApplication.prototype.loginPopup = function (request) {
        var correlationId = this.getRequestCorrelationId(request);
        this.logger.verbose("loginPopup called", correlationId);
        return this.acquireTokenPopup(__assign({ correlationId: correlationId }, (request || DEFAULT_REQUEST)));
    };
    /**
     * Silently acquire an access token for a given set of scopes. Returns currently processing promise if parallel requests are made.
     *
     * @param {@link (SilentRequest:type)}
     * @returns {Promise.<AuthenticationResult>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse} object
     */
    PublicClientApplication.prototype.acquireTokenSilent = function (request) {
        return __awaiter(this, void 0, void 0, function () {
            var correlationId, atsMeasurement, account, thumbprint, silentRequestKey, cachedResponse, response;
            var _this = this;
            return __generator(this, function (_a) {
                correlationId = this.getRequestCorrelationId(request);
                atsMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenSilent, correlationId);
                atsMeasurement.addStaticFields({
                    cacheLookupPolicy: request.cacheLookupPolicy
                });
                this.preflightBrowserEnvironmentCheck(InteractionType.Silent);
                this.logger.verbose("acquireTokenSilent called", correlationId);
                account = request.account || this.getActiveAccount();
                if (!account) {
                    throw BrowserAuthError.createNoAccountError();
                }
                thumbprint = {
                    clientId: this.config.auth.clientId,
                    authority: request.authority || Constants.EMPTY_STRING,
                    scopes: request.scopes,
                    homeAccountIdentifier: account.homeAccountId,
                    claims: request.claims,
                    authenticationScheme: request.authenticationScheme,
                    resourceRequestMethod: request.resourceRequestMethod,
                    resourceRequestUri: request.resourceRequestUri,
                    shrClaims: request.shrClaims,
                    sshKid: request.sshKid
                };
                silentRequestKey = JSON.stringify(thumbprint);
                cachedResponse = this.activeSilentTokenRequests.get(silentRequestKey);
                if (typeof cachedResponse === "undefined") {
                    this.logger.verbose("acquireTokenSilent called for the first time, storing active request", correlationId);
                    this.performanceClient.setPreQueueTime(PerformanceEvents.AcquireTokenSilentAsync, correlationId);
                    response = this.acquireTokenSilentAsync(__assign(__assign({}, request), { correlationId: correlationId }), account)
                        .then(function (result) {
                        _this.activeSilentTokenRequests.delete(silentRequestKey);
                        atsMeasurement.addStaticFields({
                            accessTokenSize: result.accessToken.length,
                            idTokenSize: result.idToken.length
                        });
                        atsMeasurement.endMeasurement({
                            success: true,
                            fromCache: result.fromCache,
                            isNativeBroker: result.fromNativeBroker,
                            cacheLookupPolicy: request.cacheLookupPolicy,
                            requestId: result.requestId,
                        });
                        return result;
                    })
                        .catch(function (error) {
                        _this.activeSilentTokenRequests.delete(silentRequestKey);
                        atsMeasurement.endMeasurement({
                            errorCode: error.errorCode,
                            subErrorCode: error.subError,
                            success: false
                        });
                        throw error;
                    });
                    this.activeSilentTokenRequests.set(silentRequestKey, response);
                    return [2 /*return*/, response];
                }
                else {
                    this.logger.verbose("acquireTokenSilent has been called previously, returning the result from the first call", correlationId);
                    // Discard measurements for memoized calls, as they are usually only a couple of ms and will artificially deflate metrics
                    atsMeasurement.discardMeasurement();
                    return [2 /*return*/, cachedResponse];
                }
            });
        });
    };
    PublicClientApplication.prototype.trackPageVisibility = function () {
        if (!this.astsAsyncMeasurement) {
            return;
        }
        this.logger.info("Perf: Visibility change detected");
        this.astsAsyncMeasurement.increment({
            visibilityChangeCount: 1,
        });
    };
    /**
     * Silently acquire an access token for a given set of scopes. Will use cached token if available, otherwise will attempt to acquire a new token from the network via refresh token.
     * @param {@link (SilentRequest:type)}
     * @param {@link (AccountInfo:type)}
     * @returns {Promise.<AuthenticationResult>} - a promise that is fulfilled when this function has completed, or rejected if an error was raised. Returns the {@link AuthResponse}
     */
    PublicClientApplication.prototype.acquireTokenSilentAsync = function (request, account) {
        var _a;
        return __awaiter(this, void 0, void 0, function () {
            var result, silentRequest, silentCacheClient, silentRequest_1, requestWithCLP_1;
            var _this = this;
            return __generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        this.performanceClient.addQueueMeasurement(PerformanceEvents.AcquireTokenSilentAsync, request.correlationId);
                        this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_START, InteractionType.Silent, request);
                        this.astsAsyncMeasurement = this.performanceClient.startMeasurement(PerformanceEvents.AcquireTokenSilentAsync, request.correlationId);
                        (_a = this.astsAsyncMeasurement) === null || _a === void 0 ? void 0 : _a.increment({
                            visibilityChangeCount: 0
                        });
                        document.addEventListener("visibilitychange", this.trackPageVisibility);
                        if (!(NativeMessageHandler.isNativeAvailable(this.config, this.logger, this.nativeExtensionProvider, request.authenticationScheme) && account.nativeAccountId)) return [3 /*break*/, 1];
                        this.logger.verbose("acquireTokenSilent - attempting to acquire token from native platform");
                        silentRequest = __assign(__assign({}, request), { account: account });
                        result = this.acquireTokenNative(silentRequest, ApiId.acquireTokenSilent_silentFlow).catch(function (e) { return __awaiter(_this, void 0, void 0, function () {
                            var silentIframeClient;
                            return __generator(this, function (_a) {
                                // If native token acquisition fails for availability reasons fallback to web flow
                                if (e instanceof NativeAuthError && e.isFatal()) {
                                    this.logger.verbose("acquireTokenSilent - native platform unavailable, falling back to web flow");
                                    this.nativeExtensionProvider = undefined; // Prevent future requests from continuing to attempt
                                    silentIframeClient = this.createSilentIframeClient(request.correlationId);
                                    return [2 /*return*/, silentIframeClient.acquireToken(request)];
                                }
                                throw e;
                            });
                        }); });
                        return [3 /*break*/, 3];
                    case 1:
                        this.logger.verbose("acquireTokenSilent - attempting to acquire token from web flow");
                        silentCacheClient = this.createSilentCacheClient(request.correlationId);
                        this.performanceClient.setPreQueueTime(PerformanceEvents.InitializeSilentRequest, request.correlationId);
                        return [4 /*yield*/, silentCacheClient.initializeSilentRequest(request, account)];
                    case 2:
                        silentRequest_1 = _b.sent();
                        requestWithCLP_1 = __assign(__assign({}, request), { 
                            // set the request's CacheLookupPolicy to Default if it was not optionally passed in
                            cacheLookupPolicy: request.cacheLookupPolicy || CacheLookupPolicy.Default });
                        this.performanceClient.setPreQueueTime(PerformanceEvents.AcquireTokenFromCache, silentRequest_1.correlationId);
                        result = this.acquireTokenFromCache(silentCacheClient, silentRequest_1, requestWithCLP_1).catch(function (cacheError) {
                            if (requestWithCLP_1.cacheLookupPolicy === CacheLookupPolicy.AccessToken) {
                                throw cacheError;
                            }
                            // block the reload if it occurred inside a hidden iframe
                            BrowserUtils.blockReloadInHiddenIframes();
                            _this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_NETWORK_START, InteractionType.Silent, silentRequest_1);
                            _this.performanceClient.setPreQueueTime(PerformanceEvents.AcquireTokenByRefreshToken, silentRequest_1.correlationId);
                            return _this.acquireTokenByRefreshToken(silentRequest_1, requestWithCLP_1).catch(function (refreshTokenError) {
                                var isServerError = refreshTokenError instanceof ServerError;
                                var isInteractionRequiredError = refreshTokenError instanceof InteractionRequiredAuthError;
                                var rtNotFound = (refreshTokenError.errorCode === InteractionRequiredAuthErrorMessage.noTokensFoundError.code);
                                var isInvalidGrantError = (refreshTokenError.errorCode === BrowserConstants.INVALID_GRANT_ERROR);
                                if ((!isServerError ||
                                    !isInvalidGrantError ||
                                    isInteractionRequiredError ||
                                    requestWithCLP_1.cacheLookupPolicy === CacheLookupPolicy.AccessTokenAndRefreshToken ||
                                    requestWithCLP_1.cacheLookupPolicy === CacheLookupPolicy.RefreshToken)
                                    && (requestWithCLP_1.cacheLookupPolicy !== CacheLookupPolicy.Skip)
                                    && !rtNotFound) {
                                    throw refreshTokenError;
                                }
                                _this.logger.verbose("Refresh token expired/invalid or CacheLookupPolicy is set to Skip, attempting acquire token by iframe.", request.correlationId);
                                _this.performanceClient.setPreQueueTime(PerformanceEvents.AcquireTokenBySilentIframe, silentRequest_1.correlationId);
                                return _this.acquireTokenBySilentIframe(silentRequest_1);
                            });
                        });
                        _b.label = 3;
                    case 3: return [2 /*return*/, result.then(function (response) {
                            var _a;
                            _this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_SUCCESS, InteractionType.Silent, response);
                            (_a = _this.astsAsyncMeasurement) === null || _a === void 0 ? void 0 : _a.endMeasurement({
                                success: true,
                                fromCache: response.fromCache,
                                isNativeBroker: response.fromNativeBroker,
                                requestId: response.requestId
                            });
                            return response;
                        }).catch(function (tokenRenewalError) {
                            var _a;
                            _this.eventHandler.emitEvent(EventType.ACQUIRE_TOKEN_FAILURE, InteractionType.Silent, null, tokenRenewalError);
                            (_a = _this.astsAsyncMeasurement) === null || _a === void 0 ? void 0 : _a.endMeasurement({
                                errorCode: tokenRenewalError.errorCode,
                                subErrorCode: tokenRenewalError.subError,
                                success: false
                            });
                            throw tokenRenewalError;
                        }).finally(function () {
                            document.removeEventListener("visibilitychange", _this.trackPageVisibility);
                        })];
                }
            });
        });
    };
    return PublicClientApplication;
}(ClientApplication));

export { PublicClientApplication };
//# sourceMappingURL=PublicClientApplication.js.map
